#include "MemPool.h"


void Mem_node::init()
{
    m_start = (uchar *)this + sizeof(Mem_node);
    m_end = (uchar *)this + PAGE_SIZE;
    m_next = nullptr;
    m_failed = 0;
    m_quote = 0;
}

//将node结点置回初始状态
void Mem_node::node_clean()
{
    m_start = (uchar *)this + sizeof(Mem_node);
    m_failed = 0;
    m_quote = 0;
}

//分配成功，引用计数+1，移动start指针
void Mem_node::node_malloc(size_t size)
{
    m_quote++;
    m_start += size;
}

//减少引用计数，若为0移动start指针
void Mem_node::node_free()
{
    m_quote--;
}

uchar *Mem_node::get_start()
{
    return m_start;
}

uchar *Mem_node::get_end()
{
    return m_end;
}

int Mem_node::get_quote()
{
    return m_quote;
}

//获取end - start的值，也就是当前块现在的可用长度
size_t Mem_node::get_len()
{
    return (m_end - m_start);
}

Mem_node *Mem_node::get_next()
{
    return m_next;
}

//每次调用get方法failed计数器自增1
int Mem_node::get_failed()
{
    m_failed++;
    return m_failed;
}

void Mem_node::set_next(Mem_node *next)
{
    m_next = next;
}

void Mem_large::large_reset(int size, void *alloc)
{
    m_size = size;
    m_alloc = alloc;
}

void Mem_large::large_free()
{
    free(m_alloc);
    m_size = 0;
    m_alloc = nullptr;
}

void Mem_large::set_next(Mem_large *next)
{
    m_next = next;
}

Mem_large *Mem_large::get_next()
{
    return m_next;
}

void *Mem_large::get_alloc()
{
    return m_alloc;
}

int Mem_large::get_size()
{
    return m_size;
}

//构造函数，创建内存池，并初始化一块自定义大小的空间
Mem_pool::Mem_pool(size_t size)
{
    if (size < PAGE_SIZE || size % PAGE_SIZE != 0)
    {
        size = PAGE_SIZE;
    }
    //posix_memalign((void **)&pool, MP_ALIGNMENT, size);
    //m_current = (Mem_node *)malloc(size);
    posix_memalign((void **)&m_current, MP_ALIGNMENT, size);
    m_head = m_current;
    m_head->init();
    m_large = nullptr;
}

//析构函数，销毁内存池，遍历各个标准块与大块，把从堆区分配的内存释放
Mem_pool::~Mem_pool()
{
    Mem_large *large = m_large;
    Mem_node *cur, *next;

    for (large; large != nullptr; large = large->get_next())
    {
        if (large->get_alloc() != nullptr)
        {
            free(large->get_alloc());
        }
    }

    cur = m_head;
    while (cur != nullptr)
    {
        next = cur->get_next();
        free(cur);
        cur = next;
    }
}

//给用户提供的申请内存空间的接口
void *Mem_pool::mp_new(size_t size)
{
    if (size <= 0)
    {
        return nullptr;
    }
    else if (size >= PAGE_SIZE - sizeof(Mem_node))          // sizeof(Mem_node) - 32
    {
        printf("New Large - %ld | PAGE_SIZE - sizeof(Mem_node): %ld\n", size, PAGE_SIZE - sizeof(Mem_node));
        return mp_new_large(size);
    }
    else
    {
        uchar *addr = nullptr;
        Mem_node *cur = m_current;

        while (cur != nullptr)
        {
            if (cur->get_len() >= size)
            {
                addr = cur->get_start();
                cur->node_malloc(size);
                return addr;
            }
            else
            {
                cur = cur->get_next();
            }
        }
        return mp_new_block(size);
    }
}

//给用户提供的申请内存空间的接口，并全部初始化为0
void *Mem_pool::mp_new_zero(size_t size)
{
    void *mem_addr = mp_new(size);
    if (mem_addr != nullptr)
    {
        memset(mem_addr, 0, size);
    }
    return mem_addr;
}

//给用户提供的释放已申请的内存空间的接口
void Mem_pool::mp_delete(void *p)
{
    Mem_large *large = m_large;
    Mem_node *node = nullptr;

    //若需要删除的是自定义块
    for (large; large != nullptr; large = large->get_next())
    {
        if (p == large->get_alloc())
        {
            large->large_free();
            return;
        }
    }

    //若要删除的是标准块
    node = m_head;
    for (node; node != nullptr; node = node->get_next())
    {
        if (((uchar *)node <= (uchar *)p) && ((uchar *)p <= (uchar *)node->get_end()))
        {
            node->node_free();
            if (node->get_quote() == 0)
            {
                m_current = m_head;
            }
            return;
        }
    }
}

//给用户提供的清空内存池中数据的接口
void Mem_pool::mp_reset_pool()
{
    Mem_node *node = nullptr;
    Mem_large *large = nullptr;

    for (large = m_large; large != nullptr; large = large->get_next())
    {
        if (large->get_alloc() != nullptr)
        {
            free(large->get_alloc());
        }
    }

    for (node = m_head; node != nullptr; node = node->get_next())
    {
        node->node_clean();
    }
    m_current = m_head;
}

//给用户提供的显示当前内存池使用情况的接口
void Mem_pool::mp_monitor(string msg)
{
    Mem_node *head = nullptr;
    Mem_large *large = nullptr;
    int i = 0;

    printf("\r\n\r\n------start monitor poll------%s\r\n\r\n", msg.c_str());
    for (head = m_head; head != nullptr; head = head->get_next())
    {
        i++;
        if (m_current == head)
        {
            cout << "current==>第" << i << "块\n";
        }

        printf("第%02d块small block  已使用:%4ld  剩余空间:%4ld  引用:%4d  failed:%4d\n", i,
               head->get_start() - (uchar *)head,
               head->get_len(), head->get_quote(), head->get_failed());
    }

    i = 0;
    for (large = m_large; large != nullptr; large = large->get_next())
    {
        i++;
        if (large->get_alloc() != nullptr)
        {
            cout << "第" << i << "块large block  size=" << large->get_size() << "\n";
        }
    }
    printf("\r\n\r\n------stop monitor poll------\r\n\r\n");
}

//向堆空间申请一块标准块空间
void *Mem_pool::mp_new_block(size_t size)
{
    int ret;
    uchar *block = nullptr;
    uchar *addr = nullptr;
    Mem_node *node = nullptr;
    Mem_node *current = m_current;
    Mem_node *cur = nullptr;

    //int ret = posix_memalign((void **)&block, MP_ALIGNMENT, PAGE_SIZE);
    //block = (uchar *)malloc(PAGE_SIZE);
    ret = posix_memalign((void **)&block, MP_ALIGNMENT, PAGE_SIZE);
    if (ret != 0)
    {
        cout << "malloc error" << endl;
        return nullptr;
    }

    node = (Mem_node *)block;
    node->init();

    addr = (uchar *)mp_align_ptr(block + sizeof(Mem_node), MP_ALIGNMENT);
    node->node_malloc(size);

    for (cur = current; cur->get_next() != nullptr; cur = cur->get_next())
    {
        if (cur->get_failed() > 4)
        {
            current = cur;
        }
    }

    cur->set_next(node);
    m_current = current;
    return addr;
}

//向堆空间申请一块长度大于标准块长度的自定义大块空间
void *Mem_pool::mp_new_large(size_t size)
{
    printf("%s | Line: %d\n", __FUNCTION__, __LINE__);

    uchar *big_addr = nullptr;
    Mem_large *large = nullptr;
    int ret;
    int n = 0;

    ret = posix_memalign((void **)&big_addr, MP_ALIGNMENT, size);
    if (ret)
    {
        return nullptr;
    }

    large = m_large;
    for (large; large != nullptr; large = large->get_next())
    {
        if (large->get_alloc() == nullptr)
        {
            large->large_reset(size, big_addr);
            return big_addr;
        }
        if (n++ > 3) //防止过多次的遍历，限制次数
        {
            break;
        }
    }

    large = (Mem_large *)mp_new(sizeof(Mem_large));

    if (large == nullptr)
    {
        free(big_addr);
        return nullptr;
    }

    large->large_reset(size, big_addr);
    //头插法
    large->set_next(m_large);
    m_large = large;

    return big_addr;
}
